package com.icloud.common.web.aspect;

import cn.hutool.json.JSON;
import cn.hutool.json.JSONUtil;
import com.icloud.common.web.annotation.AdminWhiteListOperationLog;
import com.icloud.common.web.enums.ResultEnum;
import com.icloud.common.web.util.ErrorUtil;
import com.icloud.common.web.util.IpUtil;
import com.icloud.common.web.vo.IpAddressVo;
import com.icloud.system.api.dto.SaveAdminOperationLogDto;
import com.icloud.system.api.feign.AdminWhiteListOperationLogFeignClient;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.concurrent.Executor;

@Aspect
@Component
@AllArgsConstructor
@Slf4j
public class AdminWhiteListOperationLogAop {
    private final HttpServletRequest request;
    private final AdminWhiteListOperationLogFeignClient adminWhiteListOperationLogFeignClient;
    private final Executor asyncExecutor;

    /**
     * 定义切入点
     */
    @Pointcut("@annotation(com.icloud.common.web.annotation.AdminWhiteListOperationLog)")
    public void annotationAdminWhiteListOperationLogCut() {

    }

    @Around("annotationAdminWhiteListOperationLogCut()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        Object result = null;
        String failedMessage = null;
        Throwable te = null;
        try {
            result = joinPoint.proceed();
        } catch (Throwable e) {
            te = e;
            log.error("App操作异常：{}", ErrorUtil.getErrorLog(e));
            failedMessage = ErrorUtil.getErrorLog(e);
            if (StringUtils.isNotBlank(failedMessage)) {
                failedMessage = failedMessage.replaceAll("\\s+", " ");
            }
        }
        //保存日志
        this.saveAdminWhiteListOperationLog(joinPoint, result, failedMessage);
        if (te != null) {
            throw te;
        }
        return result;
    }

    /**
     * 执行操作日志入库处理
     */
    private void saveAdminWhiteListOperationLog(ProceedingJoinPoint joinPoint, Object result, String error) {
        //从切面织入点处通过反射机制获取织入点处的方法
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        //获取切入点所在的方法
        Method method = signature.getMethod();
        //获取自定义注解OperationLog
        AdminWhiteListOperationLog annotation = method.getAnnotation(AdminWhiteListOperationLog.class);
        //注解值(操作日志描述)
        String operationLogVal = annotation.value();
        //请求方式
        String requestMethod = request.getMethod();
        String requestUri = request.getRequestURI();
        String agent = request.getHeader("User-Agent");
        //请求的方法名
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = signature.getName();
        //请求的方法参数值
        Object[] args = joinPoint.getArgs();
        //请求的方法参数名
        LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer();
        String[] paramNames = u.getParameterNames(method);
        String username = null;
        String userId = null;
        if (args != null && paramNames != null) {
            for (int i = 0; i < args.length; i++) {
                Object object = args[i];
                JSON json = JSONUtil.parse(object);
                Object usernameObj = json.getByPath("username");
                if (usernameObj != null) {
                    username = usernameObj.toString();
                }
                Object userIdObj = json.getByPath("userId");
                if (userIdObj == null) {
                    userIdObj = json.getByPath("id");
                }
                if (userIdObj != null) {
                    userId = userIdObj.toString();
                }
            }
        }
        final String finalUsername = username;
        final String finalUserId = userId;
        //IP和地址
        String ip;
        String address;
        //获取真实ip和地址
        IpAddressVo ipAddressVo = IpUtil.getIpAndAddress();
        if (null != ipAddressVo) {
            ip = ipAddressVo.getIp();
            address = ipAddressVo.getAddress();
        } else {
            address = "";
            ip = "";
        }

        asyncExecutor.execute(() -> {
            //总后台的操作日志入库
            SaveAdminOperationLogDto adminDto = new SaveAdminOperationLogDto();
            if (StringUtils.isNotBlank(finalUserId)) {
                adminDto.setAdminUserId(Long.valueOf(finalUserId));
            }
            if (StringUtils.isNotBlank(finalUsername)) {
                adminDto.setUsername(finalUsername);
            }
            //获取真实ip和地址
            adminDto.setIp(ip);
            adminDto.setAddress(address);
            adminDto.setUserAgent(agent);
            adminDto.setDesc(operationLogVal);
            adminDto.setRequestMethod(requestMethod);
            adminDto.setRequestUri(requestUri);
            adminDto.setRequestPath(className + "." + methodName);
            if (StringUtils.isNotBlank(error)) {
                adminDto.setRequestResult(ResultEnum.FAILED.getCode());
                adminDto.setFailedReason(error);
            } else {
                adminDto.setRequestResult(ResultEnum.SUCCESS.getCode());
            }
            adminWhiteListOperationLogFeignClient.saveAdminWhiteListOperationLog(adminDto);
        });
    }
}
